#region Using directives
using System;
using Microsoft.DirectX;
using SharpWind.Scene;
#endregion

namespace SharpWind.Math
{
	public class BoundingFrustrum
	{
		#region Fields

		private Plane[] planes = null;

		#endregion

		#region Constructor

		public BoundingFrustrum()
		{
			this.planes = new Plane[6];
		}

		#endregion

		#region Methods

		internal void Rebuild( Camera camera )
		{
			Matrix viewProjection = camera.ViewMatrix * camera.ProjectionMatrix;

			this.planes[0].A = viewProjection.M14 + viewProjection.M11;
			this.planes[0].B = viewProjection.M24 + viewProjection.M21;
			this.planes[0].C = viewProjection.M34 + viewProjection.M31;
			this.planes[0].D = viewProjection.M44 + viewProjection.M41;

			this.planes[1].A = viewProjection.M14 - viewProjection.M11;
			this.planes[1].B = viewProjection.M24 - viewProjection.M21;
			this.planes[1].C = viewProjection.M34 - viewProjection.M31;
			this.planes[1].D = viewProjection.M44 - viewProjection.M41;

			this.planes[2].A = viewProjection.M14 - viewProjection.M12;
			this.planes[2].B = viewProjection.M24 - viewProjection.M22;
			this.planes[2].C = viewProjection.M34 - viewProjection.M32;
			this.planes[2].D = viewProjection.M44 - viewProjection.M42;

			this.planes[3].A = viewProjection.M14 + viewProjection.M12;
			this.planes[3].B = viewProjection.M24 + viewProjection.M22;
			this.planes[3].C = viewProjection.M34 + viewProjection.M32;
			this.planes[3].D = viewProjection.M44 + viewProjection.M42;

			this.planes[4].A = viewProjection.M13;
			this.planes[4].B = viewProjection.M23;
			this.planes[4].C = viewProjection.M33;
			this.planes[4].D = viewProjection.M43;

			this.planes[5].A = viewProjection.M14 - viewProjection.M13;
			this.planes[5].B = viewProjection.M24 - viewProjection.M23;
			this.planes[5].C = viewProjection.M34 - viewProjection.M33;
			this.planes[5].D = viewProjection.M44 - viewProjection.M43;

			for( int i = 0; i < this.planes.Length; i++ )
			{
				this.planes[i] = Plane.Normalize( this.planes[i] );
			}
		}

		public bool Contains( BoundingSphere sphere )
		{
			foreach( Plane plane in this.planes )
			{
				if( plane.Dot( sphere.Center ) + sphere.Radius < 0 )
				{
					return false;
				}
			}

			return true;
		}

		#endregion

		#region Properties

		public Plane Left
		{
			get
			{
				return this.planes[0];
			}
		}

		public Plane Right
		{
			get
			{
				return this.planes[1];
			}
		}

		public Plane Top
		{
			get
			{
				return this.planes[2];
			}
		}

		public Plane Bottom
		{
			get
			{
				return this.planes[3];
			}
		}

		public Plane Near
		{
			get
			{
				return this.planes[4];
			}
		}

		public Plane Far
		{
			get
			{
				return this.planes[5];
			}
		}

		#endregion
	}
}